<template>
  <div class="min-h-screen bg-gradient-to-br from-blue-50 to-purple-50 py-8">
    <div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
      <!-- Header -->
      <div class="text-center mb-8">
        <h1 class="text-3xl font-bold text-gray-900 mb-4">
          <span class="text-gradient">HTML 实体/转义</span>
        </h1>
        <p class="text-lg text-gray-600">将文本与 HTML 实体相互转换（支持命名实体与数值实体）</p>
      </div>

      <!-- Tool Container -->
      <div class="bg-white rounded-xl shadow-lg p-6">
        <!-- Mode Selection -->
        <div class="mb-6">
          <div class="flex space-x-4">
            <button
              @click="mode = 'encode'"
              :class="mode === 'encode' ? 'primary-button' : 'secondary-button'"
              class="flex-1"
            >
              编码 (文本 → HTML 实体)
            </button>
            <button
              @click="mode = 'decode'"
              :class="mode === 'decode' ? 'primary-button' : 'secondary-button'"
              class="flex-1"
            >
              解码 (HTML 实体 → 文本)
            </button>
          </div>
        </div>

        <!-- Input Area -->
        <div class="mb-6">
          <label class="block text-sm font-medium text-gray-700 mb-2">
            {{ mode === 'encode' ? '输入文本' : '输入HTML实体/转义后的文本' }}
          </label>
          <textarea
            v-model="inputText"
            :placeholder="mode === 'encode' ? '请输入要编码的文本...' : '请输入包含实体的HTML文本等待解码...'
            "
            class="textarea-field h-32"
            @input="performConversion"
          ></textarea>
          <div class="mt-2 text-sm text-gray-500">
            字符数: {{ inputText.length }}
          </div>
        </div>

        <!-- Output Area -->
        <div class="mb-6">
          <label class="block text-sm font-medium text-gray-700 mb-2">
            {{ mode === 'encode' ? 'HTML 实体结果' : '解码后的文本' }}
          </label>
          <textarea
            v-model="outputText"
            readonly
            class="textarea-field h-32 bg-gray-50"
            :placeholder="mode === 'encode' ? '编码结果将显示在这里...' : '解码结果将显示在这里...'"
          ></textarea>
          <div class="mt-2 flex justify-between items-center">
            <span class="text-sm text-gray-500">字符数: {{ outputText.length }}</span>
            <button
              @click="copyToClipboard"
              class="secondary-button text-sm py-2 px-4"
              :disabled="!outputText"
            >
              {{ copied ? '已复制' : '复制结果' }}
            </button>
          </div>
        </div>

        <!-- Action Buttons -->
        <div class="flex flex-wrap gap-3">
          <button @click="performConversion" class="primary-button" :disabled="!inputText">
            {{ mode === 'encode' ? '编码' : '解码' }}
          </button>
          <button @click="clearAll" class="secondary-button">清空内容</button>
          <button @click="loadSample" class="secondary-button">加载示例</button>
        </div>

        <!-- Options and File Actions -->
        <div class="mt-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
          <div class="flex items-center space-x-4">
            <label class="inline-flex items-center space-x-2 text-sm text-gray-700">
              <input type="checkbox" v-model="encodeNonAscii" class="form-checkbox" />
              <span>将非 ASCII 字符转换为数值实体 (例如：&#233;)</span>
            </label>
          </div>

          <div class="flex items-center space-x-3">
            <button @click="triggerFileInput" class="secondary-button">从文件读取</button>
            <input ref="fileInputRef" type="file" class="hidden" @change="handleFileChange" />
            <button @click="downloadResult" class="secondary-button" :disabled="!outputText">下载结果</button>
          </div>
        </div>

        <!-- Error Message -->
        <div v-if="errorMessage" class="mt-4 p-3 bg-red-50 border border-red-200 rounded-lg">
          <p class="text-red-600 text-sm">{{ errorMessage }}</p>
        </div>
      </div>

      <!-- Instructions -->
      <div class="mt-8 bg-white rounded-xl shadow-lg p-6">
        <h3 class="text-lg font-semibold text-gray-900 mb-4">使用说明</h3>
        <ul class="space-y-2 text-gray-600">
          <li>• 选择“编码”或“解码”模式。</li>
          <li>• 在上方文本框输入内容，系统会自动转换并显示结果。</li>
          <li>• 编码会将特殊字符（&lt; &gt; &amp; &quot; '）转为实体，勾选选项可把非 ASCII 字符也转为数值实体。</li>
          <li>• 解码会把命名实体与数值实体转换回对应字符（例如 &amp;nbsp;、&#x4e2d; 等）。</li>
          <li>• 使用“复制结果”按钮快速复制转换后的内容。</li>
        </ul>
      </div>

      <!-- Technical Info -->
      <div class="mt-6 bg-white rounded-xl shadow-lg p-6">
        <h3 class="text-lg font-semibold text-gray-900 mb-4">技术说明</h3>
        <div class="text-gray-600 text-sm space-y-2">
          <p>本工具使用浏览器内置的 DOM 解析与文本节点实现安全的转义与解析，避免手动拼接不安全的字符串。</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'
import { useTools } from '@/composables/useTools'

const { copyToClipboard: toolsCopy, readFile, readImageFile, downloadFile } = useTools()

const mode = ref('encode')
const inputText = ref('')
const outputText = ref('')
const copied = ref(false)
const errorMessage = ref('')
const encodeNonAscii = ref(false)
const fileInputRef = ref(null)

// 执行转换
const performConversion = () => {
  errorMessage.value = ''
  if (!inputText.value) {
    outputText.value = ''
    return
  }

  try {
    if (mode.value === 'encode') {
      let encoded = escapeHtml(inputText.value)
      if (encodeNonAscii.value) {
        encoded = convertNonAsciiToEntities(encoded)
      }
      outputText.value = encoded
    } else {
      // decode using DOM
      outputText.value = unescapeHtml(inputText.value)
    }
  } catch (err) {
    errorMessage.value = (mode.value === 'encode' ? '编码失败：' : '解码失败：') + err.message
    outputText.value = ''
  }
}

// 复制到剪贴板
const copyToClipboard = async () => {
  if (!outputText.value) return
  try {
    const ok = await toolsCopy(outputText.value)
    if (ok) {
      copied.value = true
      setTimeout(() => (copied.value = false), 2000)
    } else {
    }
  } catch (err) {
  }
}

const clearAll = () => {
  inputText.value = ''
  outputText.value = ''
  errorMessage.value = ''
}

const loadSample = () => {
  if (mode.value === 'encode') {
    inputText.value = '<div>你好，& 欢迎使用 &lt;HTML 实体&gt; 工具。</div>'
  } else {
    inputText.value = '&lt;div&gt;Hello &amp; 世界 &mdash; 示例&lt;/div&gt;'
  }
  performConversion()
}

const triggerFileInput = () => {
  if (fileInputRef.value) fileInputRef.value.click()
}

const handleFileChange = async (e) => {
  const file = e.target.files && e.target.files[0]
  if (!file) return
  errorMessage.value = ''
  try {
    if (file.type.startsWith('image/')) {
      const { dataUrl } = await readImageFile(file)
      // 将 dataUrl 放入输入（通常用于 Base64，但保留能力）
      inputText.value = dataUrl
      performConversion()
    } else {
      const text = await readFile(file)
      inputText.value = text
      performConversion()
    }
  } catch (err) {
    errorMessage.value = '读取文件失败：' + err.message
  } finally {
    e.target.value = ''
  }
}

const downloadResult = () => {
  if (!outputText.value) return
  const filename = mode.value === 'encode' ? 'html-entities.txt' : 'decoded.txt'
  downloadFile(outputText.value, filename, 'text/plain')
}

// 使用 DOM 安全转义
const escapeHtml = (str) => {
  const div = document.createElement('div')
  div.appendChild(document.createTextNode(str))
  return div.innerHTML
}

// 将非 ASCII 字符替换为数值实体
const convertNonAsciiToEntities = (str) => {
  let result = ''
  for (let i = 0; i < str.length; i++) {
    const code = str.charCodeAt(i)
    if (code > 127) {
      result += `&#${code};`
    } else {
      result += str.charAt(i)
    }
  }
  return result
}

// 解码 HTML 实体（利用 innerHTML）
const unescapeHtml = (str) => {
  try {
    const div = document.createElement('div')
    // 为了解码像 &#x4e2d; 这样的十六进制实体，需要直接设置 innerHTML
    div.innerHTML = str
    return div.textContent || div.innerText || ''
  } catch (err) {
    throw new Error('无法解析输入的实体')
  }
}

// 监听模式与输入变化
watch(mode, () => {
  clearAll()
})
watch(inputText, () => {
  performConversion()
})

// SEO
useHead({
  title: 'HTML 实体转换 - 八八在线工具',
  meta: [
    { name: 'description', content: '在线 HTML 实体与文本互转工具，支持命名实体与数值实体的编码与解码' },
    { property: 'og:title', content: 'HTML 实体转换 - 八八在线工具' },
    { property: 'og:description', content: '在线 HTML 实体与文本互转工具，支持命名实体与数值实体的编码与解码' }
  ]
})
</script>
